[Design Pattern] Strategy / Policy

[디자인 패턴][행위 패턴] 전략 / 정책

Posted by ChaelinJ on May 19, 2021

Strategy

객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하는 패턴

  • 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 행위의 수정이 가능한 패턴
  • 특정 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화하여 해당 계열 안에서 상호 교체가 가능하게 하므로써 구현합니다.

다이어그램

  • Context: 알고리즘 수행을 위해 Strategy 인터페이스를 참조합니다. 알고리즘이 구현되는 방식과는 무관합니다.
  • Strategy: 지원되는 알고리즘의 공통적인 인터페이스입니다.
  • ConcreteStrategy: Strategy의 구현체

런타임 중에 사용할 알고리즘이 결정되기 때문에 Context나 Client는 실제 어떤 알고리즘이 사용되었는지 알 수 없습니다. 이를 통해 클라이언트 코드는 보다 유연해지며 재사용이 가능해 지고 중복을 피할 수 있게 됩니다.

예시와 이해

월급 계산기를 만들었습니다. 시급과 근무 일수는 구현시 편의상 통일 했으며 하루 근무 시간과 주휴수당 유무에 따라 월급을 계산하는 계산기 입니다.

주휴 수당은 아래를 기준으로 했습니다.

  • 15시간 이상 40시간 미만 근무: ([1주 총 근무시간] / 40) * 8 * [시급]
  • 40시간 이상 근무: 8 * [시급]

다이어그램입니다.

  • SimpleCalculator: 주휴수당 제외
  • ComplexCalculator: 주휴수당 포함

Employee에 Calculator 인터페이스를 저장하고 calculate() 메소드에서 calculator를 사용합니다. 즉 calculator를 클라이언트에서 결정해 같은 메소드로도 행위를 변경할 수 있게 됩니다.

Calculator - Strategy

위임을 이용해 느슨한 연결으로 전략을 자유롭게 바꿀 수 있습니다.

Employee - Context

Main - client

출력

주 5일 한달(4주) 월급---------------
하루  근무: 4
월급(주휴수당 제외): 697600
월급(주휴수당 포함): 976640

같은 시간을 근무했지만 클라이언트 선택에 따라 다른 계산 방식으로 월급을 구할 수 있습니다.

팩토리 메소드와의 차이점?

팩토리 메소드는 객체 생성 처리를 서브 클래스로 분리해서 처리하도록 캡슐화하는 패턴입니다.

전략 패턴은 런타임에 알고리즘의 교체를 통해 다른 행동을 수행하고자 하는 패턴으로 팩토리 메소드와는 목적이 다릅니다.

  • 전략 패턴: 상황에 따라 행위의 교체(객체 생성도 될 수 있음)
  • 팩토리 메소드: 상황에 따라 생성될 객체의 교체

위의 예제를 아예 EmployeeFactory를 이용하여 팩토리 메소드 패턴으로 구현한다면 Employee의 서브 클래싱을 피할 수 없습니다.

즉 주휴수당을 포함하지 않는 계산법을 사용하는 SimpleEmployee 클래스, 주휴수당을 포함하는 계산법을 사용하는 ComplexEmployee 클래스 두 개로 나뉘며 추후 수정이 필요할 경우 Employee(Context) 자체를 수정해야 하며 Context 클래스에 대한 이해가 어려워지고 유지보수가 어렵게 될 수 있습니다.

여기서 전략패턴을 사용한다면 Context와 행동 처리가 분리되어 사용자가 각각을 이해하기 쉬우며, 위임을 이용해 행동을 추가함에도 어려움이 없습니다.

성능 향상

추가적으로 위의 예제에 팩토리 메소드를 적용해 Calculator 생성 부분을 분리할 수도 있습니다.

또 추가적으로, Calculator를 싱글톤으로 변경할 수도 있습니다. 위 예제 같은 경우 Calculator 객체는 계산을 위해 사용된 후, 방법이 교체될 때마다 새로운 객체를 생성하기 때문에 메모리 낭비를 초래할 수 있습니다.

단점

  • ConcreteStrategy 클래스는 Strategy interface를 위임하고 있기 때문에 interface 변경시 모든 ConcreteStrategy 클래스의 수정이 필요합니다.

  • 통신 오버헤드가 발생할 수 있습니다. 전략 별로 다른 인자가 필요할 경우, 특정 전략에선 필요하지 않은 인자를 전달받게 될 수도 있습니다.


참고

감사합니다.

Text by Chaelin. Photographs by Chaelin, Unsplash.